import { FileService } from '@app/file';
import { PrismaService } from '@app/prisma';
import { SysTestGroupEntity } from '@app/prisma/sys.test.group.entity/sys.test.group.entity';
import { SysUserEntity } from '@app/prisma/sys.user.entity/sys.user.entity';
import { Injectable } from '@nestjs/common';

@Injectable()
export class QuestionService {
  constructor(
    private readonly file: FileService,
    private readonly prisma: PrismaService
  ) { }

  public QuestionMediaRoot = this.file.make("question")
  getQuestionMediaPath(entity: SysTestGroupEntity) {
    return this.file.join(this.QuestionMediaRoot, entity.id.toString() + ".png")
  }

  async judgePaper(
    answers: [{ id: number, answer: string }],
    questions: Map<number, { answer: string, score: number }>,
    user: SysUserEntity
  ) {
    const wrongs: Map<number, string> = new Map();
    const rights: Array<number> = [];
    let score = 0;
    for (const question of answers) {
      const right = questions.get(question.id);
      if (question.answer === right.answer) {
        score += right.score;
        rights.push(question.id);
      } else {
        wrongs.set(question.id, question.answer);
      }
    }
    const wrongsExists = await this.prisma.sys_wrong.findMany({
      where: {
        sys_userId: user.id,
        sys_test_questionId: {
          in: Array.from(wrongs.keys())
        }
      },
      select: {
        sys_test_questionId: true
      }
    })
    for (const wrong of wrongsExists) {
      if (wrongs.has(wrong.sys_test_questionId)) {
        wrongs.delete(wrong.sys_test_questionId)
      }
    }
    await this.prisma.sys_wrong.createMany({
      data: Array.from(wrongs).map(([id, answer]) => ({
        sys_userId: user.id,
        sys_test_questionId: id,
        answer
      }))
    })
    await this.prisma.sys_test_question.updateMany({
      where: {
        id: {
          in: Array.from(rights)
        }
      },
      data: {
        count: {
          increment: 1,
        },
        right: {
          increment: 1,
        }
      }
    })
    await this.prisma.sys_test_question.updateMany({
      where: {
        id: {
          in: Array.from(wrongs.keys())
        }
      },
      data: {
        count: {
          increment: 1,
        }
      }
    })
    return score;
  }

  async pushPaper(data: string, id: number, user: SysUserEntity) {
    const answers: [{ id: number, answer: string }] = JSON.parse(data);
    const paper = await this.prisma.sys_test_paper.findUnique({
      where: {
        id
      },
      include: {
        questions: true
      }
    });
    const questions: Map<number, { answer: string, score: number }> = new Map();
    for (const question of paper.questions) {
      questions.set(
        question.id,
        {
          answer: question.answer,
          score: question.score,
        }
      );
    }
    await this.prisma.sys_paper.create({
      data: {
        sys_test_paper: {
          connect: {
            id: id
          }
        },
        answers: data,
        sys_user: {
          connect: {
            id: user.id
          }
        },
      }
    })
    const score = await this.judgePaper(answers, questions, user);
    return score;
  }

  async judgeRandomPaper(data: string, user: SysUserEntity) {
    const answers: [{ id: number, answer: string }] = JSON.parse(data);
    const ids: number[] = [];
    const paper = await this.prisma.sys_test_question.findMany({
      where: {
        id: {
          in: ids
        }
      }
    });
    const questions: Map<number, { answer: string, score: number }> = new Map();
    for (const question of paper) {
      questions.set(
        question.id,
        {
          answer: question.answer,
          score: question.score,
        }
      );
    }
    const score = await this.judgePaper(answers, questions, user);
    return score;
  }

  async canReadChapter(id: number, user: SysUserEntity) {
    if (!await this.prisma.sys_user_power.findFirst({
      where: {
        sys_userId: user.id,
        sys_test_chapterId: id,
        end_time: {
          gte: new Date()
        }
      },
    })) {
      return false;
    }
    return true;
  }

  async canReadPaper(id: number, user: SysUserEntity) {
    const data = await this.prisma.sys_test_paper.findUnique({
      where: {
        id
      }
    });
    if (!data) throw new Error('试卷不存在');
    return await this.canReadChapter(data.sys_test_chapterId, user);
  }
}
